SPB Git
1import type { Metadata } from "next";2import Link from "next/link";3import { notFound, permanentRedirect } from "next/navigation";4import { getLocale } from "@/lib/i18n/server";5import { fmtDate, href, t } from "@/lib/i18n";6import { getPaper } from "@/lib/papers/queries";7import { parseIdentifier } from "@/lib/papers/identifiers";8import { AuthorsLine } from "@/components/paper-items";9export async function generateMetadata({ params }: { params: Promise<{ id: string; version: string }> }): Promise<Metadata> { const { id, version } = await params; const p = await getPaper(id); return p ? { title: `${p.identifier} ${version} · ${p.title}`, alternates: { canonical: `/papers/${p.slug}` }, robots: { index: false, follow: true } } : {}; }10export default async function VersionPage({ params }: { params: Promise<{ id: string; version: string }> }) {11  const { id, version } = await params; const locale = await getLocale(); const d = t(locale);12  const m = /^v(\d+)$/i.exec(version); if (!m) notFound();13  const parsed = parseIdentifier(id); if (parsed && parsed.slug !== id) permanentRedirect(`/papers/${parsed.slug}/${version.toLowerCase()}`);14  const p = await getPaper(id); if (!p) notFound();15  const v = p.versions.find((x) => x.version_no === Number(m[1])); if (!v) notFound();16  return (17    <article className="container py-10 max-w-3xl">18      <p className="kicker"><Link href={href(locale, `/papers/${p.slug}`)} className="no-underline hover:underline">{p.identifier}</Link> · {v.label}{v.is_current ? ` · ${d.paper.versionTable.current}` : ""}</p>19      <h1 className="mt-3 text-3xl leading-tight">{p.title}</h1>20      <p className="mt-3 text-fg-2"><AuthorsLine authors={p.authors} locale={locale} /></p>21      <dl className="mt-6 grid gap-3 sm:grid-cols-2 text-sm card p-5">22        <div><dt className="label">{d.paper.versionTable.version}</dt><dd>{v.label} (#{v.version_no})</dd></div>23        <div><dt className="label">{d.paper.versionTable.date}</dt><dd>{fmtDate(locale, v.released_on, v.released_precision as "day" | "month" | "year") || "—"}</dd></div>24        <div className="sm:col-span-2"><dt className="label">{d.paper.versionTable.description}</dt><dd className="text-fg-2">{locale === "fr" ? v.description_fr ?? v.description : v.description}</dd></div>25        <div><dt className="label">{d.paper.pagesLabel}</dt><dd>{v.pages ?? "—"}</dd></div>26        <div><dt className="label">{d.paper.sha}</dt><dd className="font-mono text-xs break-all">{v.sha256 ?? "—"}</dd></div>27      </dl>28      {v.withdrawn ? <p className="card p-4 mt-6 text-burgundy">{d.paper.versionTable.withdrawn}{v.withdrawn_reason ? ` — ${v.withdrawn_reason}` : ""}</p>29        : v.file_id ? <a href={`/api/files/${v.file_id}/${p.slug}-${v.label}.pdf`} className="btn btn-primary mt-6 no-underline">{d.paper.download} ({v.label})</a> : null}30      <p className="mt-8"><Link href={href(locale, `/papers/${p.slug}`)} className="text-navy no-underline hover:underline">← {d.misc.back}</Link></p>31    </article>32  );33}34
Files · main
Menu

Theme